package com.falcon.file.controller;

import com.falcon.file.service.IFileService;
import com.falcon.file.config.FileConfig;
import com.falcon.core.domain.BaseResponse;
import com.falcon.file.domain.dos.FileDO;
import com.falcon.file.domain.req.FileRequest;
import com.falcon.file.enums.FileTypeEnum;
import com.falcon.file.storage.IFileStorage;
import com.swan.core.constants.NumberConstant;
import com.swan.core.exception.SwanBaseException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Slf4j
@RestController
@RequestMapping("/file/load")
public class FileLoadController {

    @Autowired
    private IFileService fileService;

    @Autowired
    private IFileStorage fileUploader;

    @Autowired
    private FileConfig fileConfig;

    @PostMapping("/upload/{category}")
    public BaseResponse<Long> uploadFile(@PathVariable Integer category, MultipartFile file )  {

        // 文件名
        String fileName = file.getOriginalFilename();
        // 文件扩展名
        String fileExtension = StringUtils.substringAfterLast(fileName, ".");
        // 文件类型
        FileTypeEnum fileTypeEnum = FileTypeEnum.OfExtension(fileExtension);
        // 文件大小
        long fileSize = file.getSize();

        // 校验文件大小和文件扩展名
        if (file.getSize() > fileConfig.getMaxFileSize()) {
            throw new SwanBaseException(-1, "文件太大，不允许上传");
        }
        if (fileConfig.getAllowExtensions().contains(fileExtension)) {
            throw new SwanBaseException(-1, "不支持的文件类型");
        }

        // 存储文件
        String storageId = this.fileUploader.write(file);

        // 保存文件信息
        FileRequest request = new FileRequest();
        request.setName(fileName);
        request.setCategory(category);
        request.setSize(fileSize);
        request.setType(fileTypeEnum.getCode());
        request.setStatus(NumberConstant.ZERO);
        request.setStorageId(storageId);
        Long fileId = this.fileService.save(request);

        return BaseResponse.success(fileId);

    }

    @GetMapping("/download/{id}")
    public void fileDownload(@PathVariable Long id, HttpServletResponse response) {

        // 查询文件详情
        FileDO fileDO = this.fileService.queryInfoById(id);

        ServletOutputStream outputStream = null;
        try {
            // 处理响应头
            setDownloadHeader(fileDO.getName(), response);
            // 写入文件
            outputStream = response.getOutputStream();

            this.fileUploader.read(fileDO.getStorageId(), outputStream);

        } catch (Exception e) {
            throw new SwanBaseException();
        }

    }

    private void setDownloadHeader(String fileName, HttpServletResponse response) throws Exception{

        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);

        String encodeName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
        encodeName = encodeName.replaceAll("\\+", "%20");

        StringBuilder contentDispositionValue = new StringBuilder();
        contentDispositionValue.append("attachment; filename=")
                .append(encodeName)
                .append(";")
                .append("filename*=")
                .append("utf-8''")
                .append(encodeName);

        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
        response.setHeader("Content-disposition", contentDispositionValue.toString());
        response.setHeader("download-filename", encodeName);
    }

}

